home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2018 January / PCgo 01-2018 CD-ROM Germany.iso / nw.pak / Unnamed File 000123.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  8.7 KB  |  290 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. // require: event_target.js
  6.  
  7. cr.define('cr.ui', function() {
  8.   /** @const */ var EventTarget = cr.EventTarget;
  9.   /** @const */ var Menu = cr.ui.Menu;
  10.  
  11.   /**
  12.    * Handles context menus.
  13.    * @constructor
  14.    * @extends {cr.EventTarget}
  15.    * @implements {EventListener}
  16.    */
  17.   function ContextMenuHandler() {
  18.     this.showingEvents_ = new EventTracker();
  19.   }
  20.  
  21.   ContextMenuHandler.prototype = {
  22.     __proto__: EventTarget.prototype,
  23.  
  24.     /**
  25.      * The menu that we are currently showing.
  26.      * @type {cr.ui.Menu}
  27.      */
  28.     menu_: null,
  29.     get menu() {
  30.       return this.menu_;
  31.     },
  32.  
  33.     /**
  34.      * Shows a menu as a context menu.
  35.      * @param {!Event} e The event triggering the show (usually a contextmenu
  36.      *     event).
  37.      * @param {!cr.ui.Menu} menu The menu to show.
  38.      */
  39.     showMenu: function(e, menu) {
  40.       menu.updateCommands(assertInstanceof(e.currentTarget, Node));
  41.       if (!menu.hasVisibleItems())
  42.         return;
  43.  
  44.       this.menu_ = menu;
  45.       menu.classList.remove('hide-delayed');
  46.       menu.hidden = false;
  47.       menu.contextElement = e.currentTarget;
  48.  
  49.       // When the menu is shown we steal a lot of events.
  50.       var doc = menu.ownerDocument;
  51.       var win = doc.defaultView;
  52.       this.showingEvents_.add(doc, 'keydown', this, true);
  53.       this.showingEvents_.add(doc, 'mousedown', this, true);
  54.       this.showingEvents_.add(doc, 'touchstart', this, true);
  55.       this.showingEvents_.add(doc, 'focus', this);
  56.       this.showingEvents_.add(win, 'popstate', this);
  57.       this.showingEvents_.add(win, 'resize', this);
  58.       this.showingEvents_.add(win, 'blur', this);
  59.       this.showingEvents_.add(menu, 'contextmenu', this);
  60.       this.showingEvents_.add(menu, 'activate', this);
  61.       this.positionMenu_(e, menu);
  62.  
  63.       var ev = new Event('show');
  64.       ev.element = menu.contextElement;
  65.       ev.menu = menu;
  66.       this.dispatchEvent(ev);
  67.     },
  68.  
  69.     /**
  70.      * Hide the currently shown menu.
  71.      * @param {cr.ui.HideType=} opt_hideType Type of hide.
  72.      *     default: cr.ui.HideType.INSTANT.
  73.      */
  74.     hideMenu: function(opt_hideType) {
  75.       var menu = this.menu;
  76.       if (!menu)
  77.         return;
  78.  
  79.       if (opt_hideType == cr.ui.HideType.DELAYED)
  80.         menu.classList.add('hide-delayed');
  81.       else
  82.         menu.classList.remove('hide-delayed');
  83.       menu.hidden = true;
  84.       var originalContextElement = menu.contextElement;
  85.       menu.contextElement = null;
  86.       this.showingEvents_.removeAll();
  87.       menu.selectedIndex = -1;
  88.       this.menu_ = null;
  89.  
  90.       // On windows we might hide the menu in a right mouse button up and if
  91.       // that is the case we wait some short period before we allow the menu
  92.       // to be shown again.
  93.       this.hideTimestamp_ = cr.isWindows ? Date.now() : 0;
  94.  
  95.       var ev = new Event('hide');
  96.       ev.element = menu.contextElement;
  97.       ev.menu = menu;
  98.       this.dispatchEvent(ev);
  99.     },
  100.  
  101.     /**
  102.      * Positions the menu
  103.      * @param {!Event} e The event object triggering the showing.
  104.      * @param {!cr.ui.Menu} menu The menu to position.
  105.      * @private
  106.      */
  107.     positionMenu_: function(e, menu) {
  108.       // TODO(arv): Handle scrolled documents when needed.
  109.  
  110.       var element = e.currentTarget;
  111.       var x, y;
  112.       // When the user presses the context menu key (on the keyboard) we need
  113.       // to detect this.
  114.       if (this.keyIsDown_) {
  115.         var rect = element.getRectForContextMenu ?
  116.                        element.getRectForContextMenu() :
  117.                        element.getBoundingClientRect();
  118.         var offset = Math.min(rect.width, rect.height) / 2;
  119.         x = rect.left + offset;
  120.         y = rect.top + offset;
  121.       } else {
  122.         x = e.clientX;
  123.         y = e.clientY;
  124.       }
  125.  
  126.       cr.ui.positionPopupAtPoint(x, y, menu);
  127.     },
  128.  
  129.     /**
  130.      * Handles event callbacks.
  131.      * @param {!Event} e The event object.
  132.      */
  133.     handleEvent: function(e) {
  134.       // Keep track of keydown state so that we can use that to determine the
  135.       // reason for the contextmenu event.
  136.       switch (e.type) {
  137.         case 'keydown':
  138.           this.keyIsDown_ = !e.ctrlKey && !e.altKey &&
  139.               // context menu key or Shift-F10
  140.               (e.keyCode == 93 && !e.shiftKey ||
  141.                e.keyIdentifier == 'F10' && e.shiftKey);
  142.           break;
  143.  
  144.         case 'keyup':
  145.           this.keyIsDown_ = false;
  146.           break;
  147.       }
  148.  
  149.       // Context menu is handled even when we have no menu.
  150.       if (e.type != 'contextmenu' && !this.menu)
  151.         return;
  152.  
  153.       switch (e.type) {
  154.         case 'mousedown':
  155.           if (!this.menu.contains(e.target))
  156.             this.hideMenu();
  157.           else
  158.             e.preventDefault();
  159.           break;
  160.  
  161.         case 'touchstart':
  162.           if (!this.menu.contains(e.target))
  163.             this.hideMenu();
  164.           break;
  165.  
  166.         case 'keydown':
  167.           // keyIdentifier does not report 'Esc' correctly
  168.           if (e.keyCode == 27 /* Esc */) {
  169.             this.hideMenu();
  170.             e.stopPropagation();
  171.             e.preventDefault();
  172.  
  173.           // If the menu is visible we let it handle all the keyboard events.
  174.           } else if (this.menu) {
  175.             this.menu.handleKeyDown(e);
  176.             e.preventDefault();
  177.             e.stopPropagation();
  178.           }
  179.           break;
  180.  
  181.         case 'activate':
  182.           var hideDelayed = e.target instanceof cr.ui.MenuItem &&
  183.               e.target.checkable;
  184.           this.hideMenu(hideDelayed ? cr.ui.HideType.DELAYED :
  185.                                       cr.ui.HideType.INSTANT);
  186.           break;
  187.  
  188.         case 'focus':
  189.           if (!this.menu.contains(e.target))
  190.             this.hideMenu();
  191.           break;
  192.  
  193.         case 'blur':
  194.           this.hideMenu();
  195.           break;
  196.  
  197.         case 'popstate':
  198.         case 'resize':
  199.           this.hideMenu();
  200.           break;
  201.  
  202.         case 'contextmenu':
  203.           if ((!this.menu || !this.menu.contains(e.target)) &&
  204.               (!this.hideTimestamp_ || Date.now() - this.hideTimestamp_ > 50))
  205.             this.showMenu(e, e.currentTarget.contextMenu);
  206.           e.preventDefault();
  207.           // Don't allow elements further up in the DOM to show their menus.
  208.           e.stopPropagation();
  209.           break;
  210.       }
  211.     },
  212.  
  213.     /**
  214.      * Adds a contextMenu property to an element or element class.
  215.      * @param {!Element|!Function} elementOrClass The element or class to add
  216.      *     the contextMenu property to.
  217.      */
  218.     addContextMenuProperty: function(elementOrClass) {
  219.       var target = typeof elementOrClass == 'function' ?
  220.           elementOrClass.prototype : elementOrClass;
  221.  
  222.       target.__defineGetter__('contextMenu', function() {
  223.         return this.contextMenu_;
  224.       });
  225.       target.__defineSetter__('contextMenu', function(menu) {
  226.         var oldContextMenu = this.contextMenu;
  227.  
  228.         if (typeof menu == 'string' && menu[0] == '#') {
  229.           menu = this.ownerDocument.getElementById(menu.slice(1));
  230.           cr.ui.decorate(menu, Menu);
  231.         }
  232.  
  233.         if (menu === oldContextMenu)
  234.           return;
  235.  
  236.         if (oldContextMenu && !menu) {
  237.           this.removeEventListener('contextmenu', contextMenuHandler);
  238.           this.removeEventListener('keydown', contextMenuHandler);
  239.           this.removeEventListener('keyup', contextMenuHandler);
  240.         }
  241.         if (menu && !oldContextMenu) {
  242.           this.addEventListener('contextmenu', contextMenuHandler);
  243.           this.addEventListener('keydown', contextMenuHandler);
  244.           this.addEventListener('keyup', contextMenuHandler);
  245.         }
  246.  
  247.         this.contextMenu_ = menu;
  248.  
  249.         if (menu && menu.id)
  250.           this.setAttribute('contextmenu', '#' + menu.id);
  251.  
  252.         cr.dispatchPropertyChange(this, 'contextMenu', menu, oldContextMenu);
  253.       });
  254.  
  255.       if (!target.getRectForContextMenu) {
  256.         /**
  257.          * @return {!ClientRect} The rect to use for positioning the context
  258.          *     menu when the context menu is not opened using a mouse position.
  259.          */
  260.         target.getRectForContextMenu = function() {
  261.           return this.getBoundingClientRect();
  262.         };
  263.       }
  264.     },
  265.  
  266.     /**
  267.      * Sets the given contextMenu to the given element. A contextMenu property
  268.      * would be added if necessary.
  269.      * @param {!Element} element The element or class to set the contextMenu to.
  270.      * @param {!cr.ui.Menu} contextMenu The contextMenu property to be set.
  271.      */
  272.     setContextMenu: function(element, contextMenu) {
  273.       if (!element.contextMenu)
  274.         this.addContextMenuProperty(element);
  275.       element.contextMenu = contextMenu;
  276.     }
  277.   };
  278.  
  279.   /**
  280.    * The singleton context menu handler.
  281.    * @type {!ContextMenuHandler}
  282.    */
  283.   var contextMenuHandler = new ContextMenuHandler;
  284.  
  285.   // Export
  286.   return {
  287.     contextMenuHandler: contextMenuHandler,
  288.   };
  289. });
  290.